package org.example.aienglishapp.controller.login;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import jakarta.validation.Valid;
import org.example.aienglishapp.annotation.debounce.Debounce;
import org.example.aienglishapp.annotation.operationlog.Loggable;
import org.example.aienglishapp.dto.login.*;
import org.example.aienglishapp.entity.login.User;
import org.example.aienglishapp.entity.login.UserProfile;
import org.example.aienglishapp.mapper.login.UserMapper;
import org.example.aienglishapp.mapper.login.UserProfileMapper;
import org.example.aienglishapp.service.login.JwtUtil;
import org.example.aienglishapp.service.login.SmsService;
import org.example.aienglishapp.service.login.UserService;
import org.example.aienglishapp.util.response.ResponseResult;
import org.example.aienglishapp.util.response.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;


/**
 * @author xlj
 * @since 2024-10-1
 * @version 1.0
 */
@Slf4j
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserProfileMapper userProfileMapper;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private SmsService smsService;

    @Value("${aes.secret.key}")
    private String aesSecretKey;

    private static final Logger loginLogger = LoggerFactory.getLogger("login.logger");

    /**
     * 登录接口，用于用户名/手机号和密码登录。
     *
     * @param userLoginDTO 登录请求参数
     * @return 登录成功或失败的响应结果
     */
    @PostMapping("/login")
    public ResponseResult<?> loginUser(@RequestBody @Valid UserLoginDTO userLoginDTO) {
        try {
            // 记录登录请求
            loginLogger.info("接收到登录请求，用户名/手机号：{}", userLoginDTO.getUsernameOrPhone());

            String usernameOrPhone = userLoginDTO.getUsernameOrPhone();
            String encryptedPassword = userLoginDTO.getUserpassword();

            // 判断用户名是否为纯数字（手机号）
            if (isNumeric(usernameOrPhone)) {
                if (!isValidPhoneNumber(usernameOrPhone)) {
                    return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "手机号格式不正确");
                }

                // 通过手机号查找用户
                User foundUser = userService.findByPhoneNumber(usernameOrPhone);
                if (foundUser == null) {
                    return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "帐号或密码输入错误");
                }
                usernameOrPhone = foundUser.getUserName();
            }

            // 解密前端发送的AES加密后的密码
            String password = decryptAES(encryptedPassword, aesSecretKey);

            // 验证解密后的密码是否符合格式要求
            if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$")) {
                return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不符合格式要求：必须包含大小写字母及数字，且不少于8位，不多于20位");
            }

            try {
                // 直接从数据库中加载用户信息
                UserDetails userDetails = userDetailsService.loadUserByUsername(usernameOrPhone);

                // 检查密码是否匹配
                if (!new BCryptPasswordEncoder().matches(password, userDetails.getPassword())) {
                    throw new BadCredentialsException("密码不正确");
                }

                // 设置 SecurityContext
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities()
                );
                SecurityContextHolder.getContext().setAuthentication(authentication);

                User foundUser = userService.findByUsername(usernameOrPhone);

                // 检查用户状态
                if (foundUser.getUserStatus() != 1) {
                    return ResponseResult.failed(ResultCode.FORBIDDEN.getCode(), "您的账户当前不可用，请联系管理员");
                }

                // 更新最后登录时间
                foundUser.setLastLoginTime(new Timestamp(System.currentTimeMillis()));
                userService.updateUser(foundUser);

                // 获取角色和权限
                List<String> roles = userDetails.getAuthorities().stream()
                        .filter(grantedAuthority -> grantedAuthority.getAuthority().startsWith("ROLE_"))
                        .map(grantedAuthority -> grantedAuthority.getAuthority().substring("ROLE_".length()))
                        .collect(Collectors.toList());

                List<String> permissions = userDetails.getAuthorities().stream()
                        .filter(grantedAuthority -> grantedAuthority.getAuthority().startsWith("PERMISSION_"))
                        .map(grantedAuthority -> grantedAuthority.getAuthority().substring("PERMISSION_".length()))
                        .collect(Collectors.toList());

                // 生成 JWT 令牌
                String token = jwtUtil.generateToken(usernameOrPhone);

                // 获取用户资料
                UserProfile userProfile = userService.getUserProfile(foundUser.getUserId());

                // 创建用户响应 DTO
                UserResponseDTO response = new UserResponseDTO(
                        foundUser.getUserId(),
                        foundUser.getUserName(),
                        foundUser.getPhone(),
                        foundUser.getUserStatus(),
                        foundUser.getRegistrationTime(),
                        foundUser.getLastLoginTime(),
                        foundUser.getLastModifiedTime(),
                        foundUser.getUserPoints(),
                        foundUser.getExperiencePoints(),
                        userProfile != null ? userProfile.getNickname() : null,
                        userProfile != null ? userProfile.getUserAvatar() : null,
                        userProfile != null ? userProfile.getSignature() : null,
                        userProfile != null ? userProfile.getGender() : null,
                        userProfile != null ? userProfile.getAge() : null,
                        roles,
                        permissions,
                        token
                );

                // 记录登录成功
                loginLogger.info("登录成功，用户信息：{}", response);

                return ResponseResult.success(response);

            } catch (UsernameNotFoundException | BadCredentialsException e) {
                // 用户不存在或密码不正确
                loginLogger.warn("登录失败，无效的凭证，用户名/手机号：{}", usernameOrPhone);
                return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "帐号或密码输入错误");
            }
        } catch (Exception e) {
            // 处理其他异常情况
            loginLogger.error("登录失败，异常信息：{}", e.getMessage(), e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "系统内部错误，请稍后再试！");
        }
    }

    // 判断字符串是否为纯数字
    private boolean isNumeric(String str) {
        if (str == null) {
            return false;
        }
        for (char c : str.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }

    // 验证手机号格式
    private boolean isValidPhoneNumber(String phoneNumber) {
        // 中国手机号正则表达式
        String regex = "^1[3-9]\\d{9}$";
        return phoneNumber.matches(regex);
    }

    // AES解密方法
    private static String decryptAES(String encrypted, String base64EncodedKey) throws Exception {
        byte[] decodedKey = Base64.getDecoder().decode(base64EncodedKey);
        SecretKeySpec secretKey = new SecretKeySpec(decodedKey, "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted));
        return new String(original, "UTF-8");
    }

    /**
     * 发送验证码到指定的手机号码，并将验证码存储以便后续验证。
     * 使用防抖处理，确保30秒内不会重复发送。
     *
     * @param request 包含手机号码的请求体
     * @return 返回操作结果
     */
    @PreAuthorize("permitAll()")
    @PostMapping("/verificationcode")
    @Debounce(interval = 30 * 1000) // 防抖30秒
    public ResponseResult<Void> sendVerificationCode(@RequestBody VerificationCodeLoginRequest request) {
        String phoneNumber = request.getPhoneNumber();
        String verificationCode = smsService.generateVerificationCode();

        log.info("从前端获取的手机号为：{}", phoneNumber);

        try {
            SendSmsResponse response = smsService.sendSms(phoneNumber, verificationCode);
            if ("OK".equals(response.getCode())) {
                // 存储验证码到缓存或数据库中，以便后续验证
                smsService.storeVerificationCode(phoneNumber, verificationCode);
                return ResponseResult.success();
            } else {
                return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "发送验证码失败：" + response.getMessage());
            }
        } catch (ClientException e) {
            log.error("发送验证码时出现异常：", e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "发送验证码失败：" + e.getMessage());
        }
    }

    /**
     * 验证码登录接口。
     *
     * @param request 验证码登录请求参数
     * @return 登录成功或失败的响应结果
     */
    @PreAuthorize("permitAll()")
    @PostMapping("/login/verificationcode")
    public ResponseResult<?> verifyLogin(@RequestBody VerificationCodeLoginRequest request) {
        String phoneNumber = request.getPhoneNumber();
        String verificationCode = request.getVerificationCode();

        try {
            // 记录登录请求
            loginLogger.info("接收到验证码登录请求，手机号：{}", phoneNumber);

            // 验证验证码
            boolean isValid = smsService.validateVerificationCode(phoneNumber, verificationCode);
            if (!isValid) {
                return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "验证码无效");
            }

            // 验证码有效，进行登录
            User user = userService.findByPhoneNumber(phoneNumber);
            if (user == null) {
                return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "手机号未注册");
            }

            // 检查用户状态
            if (user.getUserStatus() != 1) {
                return ResponseResult.failed(ResultCode.FORBIDDEN.getCode(), "您的账户当前不可用，请联系管理员");
            }

            // 设置 SecurityContext
            UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUserName());
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities()
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 更新最后登录时间
            user.setLastLoginTime(new Timestamp(System.currentTimeMillis()));
            userService.updateUser(user);

            // 生成 JWT 令牌
            String token = jwtUtil.generateToken(user.getUserName());

            // 获取角色和权限
            List<String> roles = userDetails.getAuthorities().stream()
                    .filter(grantedAuthority -> grantedAuthority.getAuthority().startsWith("ROLE_"))
                    .map(grantedAuthority -> grantedAuthority.getAuthority().substring("ROLE_".length()))
                    .collect(Collectors.toList());

            List<String> permissions = userDetails.getAuthorities().stream()
                    .filter(grantedAuthority -> grantedAuthority.getAuthority().startsWith("PERMISSION_"))
                    .map(grantedAuthority -> grantedAuthority.getAuthority().substring("PERMISSION_".length()))
                    .collect(Collectors.toList());

            // 获取用户资料
            UserProfile userProfile = userService.getUserProfile(user.getUserId());

            // 创建用户响应 DTO
            UserResponseDTO response = new UserResponseDTO(
                    user.getUserId(),
                    user.getUserName(),
                    user.getPhone(),
                    user.getUserStatus(),
                    user.getRegistrationTime(),
                    user.getLastLoginTime(),
                    user.getLastModifiedTime(),
                    user.getUserPoints(),
                    user.getExperiencePoints(),
                    userProfile != null ? userProfile.getNickname() : null,
                    userProfile != null ? userProfile.getUserAvatar() : null,
                    userProfile != null ? userProfile.getSignature() : null,
                    userProfile != null ? userProfile.getGender() : null,
                    userProfile != null ? userProfile.getAge() : null,
                    roles,
                    permissions,
                    token
            );

            // 记录登录成功
            loginLogger.info("验证码登录成功，用户信息：{}", response);

            return ResponseResult.success(response);

        } catch (Exception e) {
            // 处理其他异常情况
            loginLogger.error("验证码登录失败，异常信息：{}", e.getMessage(), e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "系统内部错误，请稍后再试！");
        }
    }

    /**
     * 用户名注册接口。
     * 此接口用于接收用户注册请求，包括验证用户名是否已存在、解密密码并验证格式、创建用户及用户资料，并保存到数据库中。
     *
     * @param userRegisterDTO 用户注册信息的数据传输对象，包含用户名和加密后的密码
     * @return 返回操作结果，包括成功或失败的状态码和消息
     */
    @Loggable("用户注册")
    @Transactional
    @PostMapping("/register")
    public ResponseResult<Void> registerUser(@RequestBody @Valid UsernameRegisterDTO userRegisterDTO) {
        // 检查用户名是否存在
        if (userService.checkUsernameExists(userRegisterDTO.getUsername())) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户名已存在");
        }

        String encryptedPassword = userRegisterDTO.getUserpassword();

        // 解密前端发送的AES加密后的密码
        String password;
        try {
            password = decryptAES(encryptedPassword, aesSecretKey);
        } catch (Exception e) {
            log.error("解密密码时发生错误", e);
            throw new RuntimeException(e);
        }

        // 验证解密后的密码是否符合格式要求
        if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$")) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不符合格式要求：必须包含大小写字母及数字，且不少于8位，不多于20位");
        }

        // 创建用户实例
        User newUser = new User();
        newUser.setUserName(userRegisterDTO.getUsername());
        newUser.setUserPassword(password);

        try {
            // 使用 UserService 注册用户，并保存到数据库（完成持久化）
            userService.registerUser(newUser);

            // 确保 userId 可用
            Long userId = newUser.getUserId();
            if (userId == null) {
                throw new IllegalStateException("用户ID未能正确生成");
            }

            log.info("将要从数据库用户表中找的UserId 为：{}", userId);

            // 从数据库中查询用户，以确认其 ID
            User persistedUser = userMapper.findById(userId)
                    .orElseThrow(() -> new IllegalStateException("用户未能从数据库中找到"));

            log.info("用户已保存，ID: {}", userId);

            // 创建用户资料实例
            UserProfile newUserProfile = new UserProfile();
            newUserProfile.setUserId(persistedUser.getUserId());
            newUserProfile.setNickname(persistedUser.getUserName());
            newUserProfile.setUserAvatar(null);
            newUserProfile.setSignature(null);
            newUserProfile.setGender(null);
            newUserProfile.setAge(null);

            log.info("将要插入的用户资料：{}", newUserProfile);

            // 保存用户资料信息
            userProfileMapper.insert(newUserProfile);

            log.info("用户资料已插入，ID: {}", newUserProfile.getUserId());

            // 返回注册成功信息
            return ResponseResult.success();
        } catch (Exception e) {
            log.error("注册过程中发生错误: {}", e.getMessage(), e);
            // 如果发生异常，返回错误信息
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "注册失败，请重试或联系管理员。");
        }
    }

    /**
     * 验证码注册接口。
     * 此接口用于接收用户通过手机号和验证码进行注册的请求，包括验证手机号是否已存在、验证验证码有效性、解密并验证密码格式、创建用户及用户资料，并保存到数据库中。
     *
     * @param verificationCodeRegisterDTO 包含手机号、验证码和加密后的密码的数据传输对象
     * @return 返回操作结果，包括成功或失败的状态码和消息
     */
    @Loggable("验证码注册")
    @Transactional
    @PostMapping("/register/verificationcode")
    public ResponseResult<Void> registerByVerification(@RequestBody @Valid VerificationCodeRegisterDTO verificationCodeRegisterDTO) {
        // 检查手机号是否存在
        if (userService.checkPhoneNumberExists(verificationCodeRegisterDTO.getPhoneNumber())) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "该手机号已注册");
        }

        // 验证验证码
        boolean isValid = smsService.validateVerificationCode(verificationCodeRegisterDTO.getPhoneNumber(), verificationCodeRegisterDTO.getVerificationCode());
        if (!isValid) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "验证码无效或已过期");
        }

        String encryptedPassword = verificationCodeRegisterDTO.getUserpassword();

        // 解密前端发送的AES加密后的密码
        String password;
        try {
            password = decryptAES(encryptedPassword, aesSecretKey);
        } catch (Exception e) {
            log.error("解密密码时发生错误", e);
            throw new RuntimeException(e);
        }

        // 验证解密后的密码是否符合格式要求
        if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$")) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不符合格式要求：必须包含大小写字母及数字，且不少于8位，不多于20位");
        }

        // 创建用户实例
        User newUser = new User();
        newUser.setUserName(verificationCodeRegisterDTO.getPhoneNumber());
        newUser.setUserPassword(password);
        newUser.setPhone(verificationCodeRegisterDTO.getPhoneNumber());

        try {
            // 使用 UserService 注册用户，并保存到数据库（完成持久化）
            userService.registerUser(newUser);

            // 确保 userId 可用
            Long userId = newUser.getUserId();
            if (userId == null) {
                throw new IllegalStateException("用户ID未能正确生成");
            }

            log.info("将要从数据库用户表中找的UserId 为：{}", userId);

            // 从数据库中查询用户，以确认其 ID
            User persistedUser = userMapper.findById(userId)
                    .orElseThrow(() -> new IllegalStateException("用户未能从数据库中找到"));

            log.info("用户已保存，ID: {}", userId);

            // 创建用户资料实例
            UserProfile newUserProfile = new UserProfile();
            newUserProfile.setUserId(persistedUser.getUserId());
            newUserProfile.setNickname(persistedUser.getUserName());
            newUserProfile.setUserAvatar(null);
            newUserProfile.setSignature(null);
            newUserProfile.setGender(null);
            newUserProfile.setAge(null);

            log.info("将要插入的用户资料：{}", newUserProfile);

            // 保存用户资料信息
            userProfileMapper.insert(newUserProfile);

            log.info("用户资料已插入，ID: {}", newUserProfile.getUserId());

            // 返回注册成功信息
            return ResponseResult.success();
        } catch (Exception e) {
            log.error("注册过程中发生错误: {}", e.getMessage(), e);
            // 如果发生异常，返回错误信息
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "注册失败，请重试或联系管理员。");
        }
    }

    /**
     * 密码重置接口。
     * 此接口用于接收用户通过手机号和验证码进行密码重置的请求，包括验证手机号是否已注册、验证验证码有效性、解密并验证新密码格式、更新用户密码。
     *
     * @param resetPasswordRequest 包含手机号、验证码和加密后的新密码的数据传输对象
     * @return 返回操作结果，包括成功或失败的状态码和消息
     */
    @PostMapping("/reset-password")
    public ResponseResult<Void> resetPassword(@RequestBody @Valid ResetPasswordRequestDTO resetPasswordRequest) {
        log.info("接收到密码重置请求: {}", resetPasswordRequest);

        // 检查手机号是否存在
        if (!userService.checkPhoneNumberExists(resetPasswordRequest.getPhoneNumber())) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "该手机号未注册");
        }

        // 验证验证码
        boolean isValid = smsService.validateVerificationCode(resetPasswordRequest.getPhoneNumber(), resetPasswordRequest.getVerificationCode());
        if (!isValid) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "验证码无效或已过期");
        }

        String encryptedPassword = resetPasswordRequest.getNewPassword();

        // 解密前端发送的AES加密后的密码
        String newPassword;
        try {
            newPassword = decryptAES(encryptedPassword, aesSecretKey);
        } catch (Exception e) {
            log.error("解密密码时发生错误", e);
            throw new RuntimeException(e);
        }

        // 验证解密后的密码是否符合格式要求
        if (!newPassword.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$")) {
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不符合格式要求：必须包含大小写字母及数字，且不少于8位，不多于20位");
        }

        // 获取用户
        User user = userService.findByPhoneNumber(resetPasswordRequest.getPhoneNumber());

        // 更新用户密码
        try {
            String encodedPassword = passwordEncoder.encode(newPassword);
            user.setUserPassword(encodedPassword);
            userService.updateUser(user);

            log.info("密码重置成功，用户手机号: {}", resetPasswordRequest.getPhoneNumber());

            // 返回密码重置成功信息
            return ResponseResult.success();
        } catch (Exception e) {
            log.error("密码重置过程中发生错误: {}", e.getMessage(), e);
            // 如果发生异常，返回错误信息
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "密码重置失败，请重试或联系管理员。");
        }
    }


    /**
     * 验证用户的原密码。
     *
     * @param requestBody 包含用户ID和原密码的请求体
     * @return 验证成功或失败的响应结果
     */
    @PostMapping("/validate-password")
    public ResponseResult<Void> validatePassword(@RequestBody Map<String, String> requestBody) {
        // 获取并转换 userId
        String userIdStr = requestBody.get("userId");
        Long userId;
        try {
            userId = Long.parseLong(userIdStr);
        } catch (NumberFormatException e) {
            log.warn("验证原密码失败：无效的用户ID格式");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "无效的用户ID格式");
        }

        String oldPassword = requestBody.get("oldPassword");

        // 检查 userId 和 oldPassword 是否为空
        if (userId == null || oldPassword == null || oldPassword.isEmpty()) {
            log.warn("验证原密码失败：用户ID或原密码为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户ID或原密码不能为空");
        }

        // 查询用户信息
        User user = userMapper.findById(userId)
                .orElseThrow(() -> {
                    log.warn("验证原密码失败：用户未找到，userId={}", userId);
                    return new IllegalStateException("用户未找到");
                });

        // 验证原密码
        if (BCrypt.checkpw(oldPassword, user.getUserPassword())) {
            log.info("成功验证用户id {} 的原密码", userId);
            return ResponseResult.success();
        } else {
            log.warn("验证原密码失败：原密码不正确，userId={}", userId);
            return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "原密码不正确");
        }
    }

    /**
     * 更新用户的手机号码。
     *
     * @param request 包含用户ID、新手机号码和验证码的请求体
     * @return 更新成功后的响应结果
     */
    @PostMapping("phonenumber")
    public ResponseResult<Void> updatePhoneNumber(@RequestBody Map<String, Object> request) {
        // 安全地获取并转换userId
        Object userIdObj = request.get("userId");
        Long userId;
        if (userIdObj instanceof Integer) {
            userId = ((Integer) userIdObj).longValue();
        } else if (userIdObj instanceof Long) {
            userId = (Long) userIdObj;
        } else {
            log.warn("更新手机号失败：无效的用户ID");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "无效的用户ID");
        }

        String newPhoneNumber = (String) request.get("phoneNumber");
        String verificationCode = (String) request.get("verificationCode");

        // 检查新手机号是否为空
        if (newPhoneNumber == null || newPhoneNumber.isEmpty()) {
            log.warn("更新手机号失败：请输入新的手机号码");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "请输入新的手机号码");
        }

        // 验证新手机号格式
        if (!isValidPhoneNumber(newPhoneNumber)) {
            log.warn("更新手机号失败：请输入有效的手机号码");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "请输入有效的手机号码");
        }

        // 检查验证码是否为空
        if (verificationCode == null || verificationCode.isEmpty()) {
            log.warn("更新手机号失败：请输入验证码");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "请输入验证码");
        }

        // 确保 userId 不为空
        if (userId == null) {
            log.warn("更新手机号失败：用户ID不能为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户ID不能为空");
        }

        // 验证验证码
        boolean isValid = smsService.validateVerificationCode(newPhoneNumber, verificationCode);
        if (!isValid) {
            log.warn("更新手机号失败：验证码无效或已过期");
            return ResponseResult.failed(HttpStatus.UNAUTHORIZED.value(), "验证码无效或已过期");
        }

        // 调用服务层方法更新手机号
        userService.updateUserPhoneNumber(userId, newPhoneNumber);
        log.info("成功更新用户id {} 的手机号为 {}", userId, newPhoneNumber);

        return ResponseResult.success();
    }

    /**
     * 用户注销。
     *
     * @param userId 用户的唯一标识符
     * @param request 包含密码的请求体
     * @return 注销成功后的响应结果
     */
    @Loggable("用户注销")
    @PutMapping("/{userId}/logout")
    public ResponseResult<Void> logoutUser(@PathVariable Long userId, @RequestBody Map<String, String> request) {
        String password = request.get("password");

        if (password == null || password.isEmpty()) {
            log.warn("用户注销失败：密码为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不能为空");
        }

        userService.logoutUser(userId, password);
        log.info("成功注销用户id {}", userId);

        return ResponseResult.success();
    }

    /**
     * 更新指定用户的密码。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含新密码的请求体
     * @return 更新成功后的响应结果
     */
    @Loggable("更新密码")
    @PutMapping("/{userId}/password")
    public ResponseResult<Void> updateUserPassword(@PathVariable Long userId, @RequestBody Map<String, String> requestBody) {
        String newPassword = requestBody.get("newPassword");

        if (newPassword == null || newPassword.isEmpty()) {
            log.warn("更新用户密码失败：新密码为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "新密码不能为空");
        }

        // 验证新密码是否符合格式要求
        if (!newPassword.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$")) {
            log.warn("更新用户密码失败：密码不符合格式要求");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不符合格式要求：必须包含大小写字母及数字，且不少于8位，不多于20位");
        }

        userService.updateUserPassword(userId, newPassword);
        log.info("成功更新用户id {} 的密码", userId);

        return ResponseResult.success();
    }

    /**
     * 获取所有用户（不分页）。
     *
     * @return 包含所有用户的响应结果
     */
    @GetMapping
    public ResponseResult<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        log.info("返回的用户列表: {}", users);

        if (users == null || users.isEmpty()) {
            log.info("未找到任何用户");
            return ResponseResult.success(Collections.emptyList());
        }

        return ResponseResult.success(users);
    }

    /**
     * 根据用户名搜索用户。
     *
     * @param username 要搜索的用户名
     * @return 包含用户信息的响应结果
     */
    @GetMapping("/search")
    public ResponseResult<User> searchUsersByUsername(@RequestParam String username) {
        if (username == null || username.isEmpty()) {
            log.warn("搜索用户失败：用户名为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户名不能为空");
        }

        Optional<User> user = Optional.ofNullable(userMapper.findByUserName(username));

        if (user.isPresent()) {
            log.info("成功找到用户名为 {} 的用户", username);
            return ResponseResult.success(user.get());
        } else {
            log.info("未找到用户名为 {} 的用户", username);
            return ResponseResult.failed(404, "未找到该用户名对应的用户");
        }
    }

    /**
     * 添加新用户。
     *
     * @param userRequest 包含用户信息的请求体
     * @return 添加成功后的响应结果
     */
    @Loggable("添加用户")
    @PostMapping("/adduser")
    @Transactional
    public ResponseResult<Void> addUser(@RequestBody @Valid AddUserRequestDTO userRequest) {
        // 检查用户名是否存在
        if (userService.checkUsernameExists(userRequest.getUserName())) {
            log.warn("添加用户失败：用户名已存在");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户名已存在");
        }

        // 解密前端发送的AES加密后的密码
        String password;
        try {
            password = decryptAES(userRequest.getUserPassword(), aesSecretKey);
        } catch (Exception e) {
            log.error("解密密码时发生错误: {}", e.getMessage(), e);
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "解密密码失败，请检查输入");
        }

        // 验证解密后的密码是否符合格式要求
        if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$")) {
            log.warn("添加用户失败：密码不符合格式要求");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "密码不符合格式要求：必须包含大小写字母及数字，且不少于8位，不多于20位");
        }

        // 创建用户实例
        User newUser = new User();
        newUser.setUserName(userRequest.getUserName());
        newUser.setUserPassword(password);

        // 使用 UserService 注册用户, 并保存到数据库(完成持久化)
        userService.registerUser(newUser);

        // 确保 userId 可用
        Long userId = newUser.getUserId();
        if (userId == null) {
            throw new IllegalStateException("用户ID未能正确生成");
        }

        // 从数据库中查询用户，以确认其 ID
        User persistedUser = userMapper.findById(userId)
                .orElseThrow(() -> new IllegalStateException("用户未能从数据库中找到"));

        // 创建用户资料实例
        UserProfile newUserProfile = new UserProfile();
        newUserProfile.setUserId(persistedUser.getUserId());

        // 如果前端传的昵称为空，就把昵称设置为和用户名一样
        String nickname = userRequest.getNickname() != null ? userRequest.getNickname() : newUser.getUserName();
        newUserProfile.setNickname(nickname);
        newUserProfile.setGender(userRequest.getGender());
        newUserProfile.setAge(userRequest.getAge());
        newUserProfile.setUserAvatar(null);
        newUserProfile.setSignature(null);

        // 保存用户资料信息
        userProfileMapper.insert(newUserProfile);

        log.info("成功添加用户id {}，用户名为 {}", userId, newUser.getUserName());

        return ResponseResult.success();
    }

    /**
     * 删除指定的用户。
     *
     * @param requestBody 包含要删除用户ID列表的请求体
     * @return 删除成功后的响应结果
     */
    @Loggable("删除用户")
    @Transactional
    @DeleteMapping("/delete")
    public ResponseResult<Void> deleteUser(@RequestBody Map<String, List<Long>> requestBody) {
        List<Long> userIds = requestBody.get("userIds");

        if (userIds == null || userIds.isEmpty()) {
            log.warn("删除用户失败：用户ID列表为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户ID列表不能为空");
        }

        userService.deleteUsers(userIds);
        log.info("成功删除用户ID列表中的用户: {}", userIds);

        return ResponseResult.success();
    }

    /**
     * 更新指定用户的状态。
     *
     * @param userId 用户的唯一标识符
     * @param status 新的状态值
     * @return 更新成功后的响应结果
     */
    @Loggable("更新用户状态")
    @PutMapping("/{userId}/status")
    public ResponseResult<Void> updateUserStatus(@PathVariable Long userId, @RequestParam Integer status) {
        if (status == null || status < 0) {
            log.warn("更新用户状态失败：无效的状态值");
            return ResponseResult.failed(400, "状态值必须为非负整数");
        }

        userService.updateUserStatus(userId, status);
        log.info("成功更新用户id {} 的状态为 {}", userId, status);

        return ResponseResult.success();
    }

    /**
     * 检查指定的用户名是否存在。
     *
     * @param username 要检查的用户名
     * @return 包含用户名存在状态的响应结果
     */
    @GetMapping("/exists/{username}")
    public ResponseResult<Boolean> checkUsernameExists(@PathVariable String username) {
        if (username == null || username.isEmpty()) {
            log.warn("检查用户名失败：用户名为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户名不能为空");
        }

        Boolean exists = userService.checkUsernameExists(username);
        log.info("检查用户名 {} 的结果为 {}", username, exists);

        return ResponseResult.success(exists);
    }

    /**
     * 更新指定用户的昵称。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含新昵称的请求体
     * @return 更新成功后的响应结果
     */
    @Loggable("更新昵称")
    @PutMapping("/{userId}/nickname")
    @Debounce(interval = 500)
    public ResponseResult<Void> updateUserNickname(@PathVariable Long userId, @RequestBody Map<String, String> requestBody) {
        String nickname = requestBody.get("nickname");

        if (nickname == null || nickname.isEmpty()) {
            log.warn("更新用户昵称失败：昵称为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "昵称不能为空");
        }

        userService.updateUserNickname(userId, nickname);
        log.info("成功更新用户id {} 的昵称为 {}", userId, nickname);

        return ResponseResult.success();
    }

    /**
     * 更新指定用户的性别。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含新性别的请求体
     * @return 更新成功后的响应结果
     */
    @Transactional
    @PutMapping("/{userId}/gender")
    public ResponseResult<Void> updateUserGender(@PathVariable Long userId, @RequestBody Map<String, Object> requestBody) {
        log.info("接收到更新用户 {} 性别的请求", userId);

        String gender = (String) requestBody.get("gender");

        if (!"男".equalsIgnoreCase(gender) && !"女".equalsIgnoreCase(gender)) {
            log.warn("更新用户性别失败：无效的性别值");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "无效的性别值");
        }

        gender = gender.trim();
        userService.updateUserGender(userId, gender);
        log.info("成功更新用户id {} 的性别为 {}", userId, gender);

        return ResponseResult.success();
    }

    /**
     * 更新指定用户的年龄。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含新年龄的请求体
     * @return 更新成功后的响应结果
     */
    @PutMapping("/{userId}/age")
    public ResponseResult<Void> updateUserAge(@PathVariable Long userId, @RequestBody Map<String, Integer> requestBody) {
        Integer age = requestBody.get("age");

        if (age == null || age <= 0) {
            log.warn("更新用户年龄失败：无效的年龄值");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "年龄必须为正整数");
        }

        userService.updateUserAge(userId, age);
        log.info("成功更新用户id {} 的年龄为 {}", userId, age);

        return ResponseResult.success();
    }

    /**
     * 更新指定用户的签名。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含新签名的请求体
     * @return 更新成功后的响应结果
     */
    @PutMapping("/{userId}/signature")
    public ResponseResult<Void> updateUserSignature(@PathVariable Long userId, @RequestBody Map<String, String> requestBody) {
        String signature = requestBody.get("signature");

        userService.updateUserSignature(userId, signature);
        log.info("成功更新用户 {} 的签名", userId);

        return ResponseResult.success();
    }

    /**
     * 更新指定用户的用户名。
     *
     * @param userId 用户的唯一标识符
     * @param requestBody 包含新用户名的请求体
     * @return 更新成功后的响应结果
     */
    @Loggable("更新用户名")
    @PutMapping("/{userId}/username")
    public ResponseResult<Void> updateUserUsername(@PathVariable Long userId, @RequestBody Map<String, String> requestBody) {
        String username = requestBody.get("username");

        if (username == null || username.isEmpty()) {
            log.warn("更新用户名失败：用户名为空");
            return ResponseResult.failed(ResultCode.BAD_REQUEST.getCode(), "用户名不能为空");
        }

        userService.updateUserUsername(userId, username);
        log.info("成功更新用户id {} 的用户名为 {}", userId, username);

        return ResponseResult.success();
    }

    /**
     * 获取当前用户的权限信息。
     *
     * @return 包含用户角色和权限信息的响应结果
     */
    @GetMapping("/getUserPermissions")
    public ResponseResult<Map<String, Object>> getUserPermissions() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication == null || !authentication.isAuthenticated()) {
                log.warn("获取用户权限失败：未授权");
                return ResponseResult.failed(ResultCode.UNAUTHORIZED.getCode(), "未授权");
            }

            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            List<String> roles = userDetails.getAuthorities().stream()
                    .filter(grantedAuthority -> !grantedAuthority.getAuthority().startsWith("PERMISSION_"))
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());

            List<String> permissions = userDetails.getAuthorities().stream()
                    .filter(grantedAuthority -> !grantedAuthority.getAuthority().startsWith("ROLE_"))
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());

            Map<String, Object> response = new HashMap<>();
            response.put("roles", roles);
            response.put("permissions", permissions);

            log.info("成功获取用户权限信息，角色数量：{}, 权限数量: {}", roles.size(), permissions.size());
            return ResponseResult.success(response);

        } catch (Exception e) {
            log.error("获取用户权限时出现异常：", e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "获取用户权限失败");
        }
    }

    //验证密码是否合法
    private boolean validatePassword(String password) {
        // 密码必须包含大小写字母及数字，且不少于8位，不多于20位
        String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$";
        return password != null && password.matches(regex);
    }
}